﻿using System;
using System.Collections.Generic;

namespace Camstar.Utils.csv.Data
{
    /// <summary>
    /// A simple name space provider.
    /// </summary>
    public class SimpleNameSpace : INameSpace
    {
        #region Constructors

        /// <summary>
        /// Construct a simple case-sensitive name space.
        /// </summary>
        public SimpleNameSpace()
            : this(DefaultCapacity, false)
        {
        }

        /// <summary>
        /// Construct a simple case-sensitive name space with the specified initial capacity.
        /// </summary>
        /// <param name="capacity">The initial capacity of the name space dictionary.</param>
        public SimpleNameSpace(
            int capacity)
            : this(capacity, false)
        {
        }

        /// <summary>
        /// Construct a simple name space with the specified case-sensitivity.
        /// </summary>
        /// <param name="noCase">A value indicating if the dictionary is case-insensitive.</param>
        public SimpleNameSpace(
            bool noCase)
            : this(DefaultCapacity, noCase)
        {
        }

        /// <summary>
        /// Construct a simple name space with the specified case-sensitivity and initial capacity.
        /// </summary>
        /// <param name="capacity">The initial capacity of the name space dictionary.</param>
        /// <param name="noCase">A value indicating if the dictionary is case-insensitive.</param>
        public SimpleNameSpace(
            int capacity,
            bool noCase)
            : this(capacity, noCase ? StringComparer.CurrentCultureIgnoreCase : StringComparer.CurrentCulture)
        {
        }

        /// <summary>
        /// Construct a simple name space with the specified key comparer and initial capacity.
        /// </summary>
        /// <param name="capacity">The initial capacity of the name space dictionary.</param>
        /// <param name="comparer">The method used to compare to key values in the dictionary.</param>
        public SimpleNameSpace(
            int capacity,
            IEqualityComparer<string> comparer)
        {
            names = new Dictionary<string, bool>(capacity, comparer);
            DefaultBaseName = "Column";
        }

        #endregion // Constructors

        #region Constants

        /// <summary>
        /// The default initial capacity for this name space.
        /// </summary>
        public const int DefaultCapacity = 1023;

        #endregion // Constants

        #region Private data

        /// <summary>
        /// The keys for this name space.
        /// </summary>
        private readonly Dictionary<string, bool> names;

        /// <summary>
        /// The next tie breaker value to use when names are not unique.
        /// </summary>
        private int tieBreaker;

        #endregion // Private data

        #region Properties

        /// <summary>
        /// Gets the default base name to use when no base name is provided.
        /// </summary>
        public string DefaultBaseName { get; protected set; }

        /// <summary>
        /// Gets 
        /// </summary>
        public int GeneratedCount { get; private set; }

        #endregion // Properties

        #region INameSpace Members

        /// <summary>
        /// Gets a collection of names in the name space (the order of the collection is undefined).
        /// </summary>
        public ICollection<string> Names
        {
            get { return names.Keys; }
        }

        /// <summary>
        /// Clean a name so that is safe for usage.
        /// </summary>
        /// <param name="name">The name to be cleaned.</param>
        /// <returns>The safe name.</returns>
        public virtual string CleanName(
            string name)
        {
            return name;
        }

        /// <summary>
        /// Gets a value indicating if the specified name is in use.
        /// </summary>
        /// <param name="name">The name to be tested.</param>
        /// <returns>True, if the name exists in the namespace; otherwise, false.</returns>
        public bool ContainsName(
            string name)
        {
            return names.ContainsKey(name);
        }

        /// <summary>
        /// Create a unique name.
        /// </summary>
        public string CreateName()
        {
            return CreateName(null);
        }

        /// <summary>
        /// Create a unique name.
        /// </summary>
        /// <param name="baseName">The base name used during creation (or null).</param>
        /// <returns>A unique name.</returns>
        public virtual string CreateName(
            string baseName)
        {
            // Start at the beginning
            string name = baseName;

            // If no base name...
            if (baseName == null)
            {
                // Use default base name
                baseName = DefaultBaseName;

                // Use the first name
                name = String.Format("{0}-{1}",
                                     DefaultBaseName, ++tieBreaker);
            } // If no base name...

            // Loop to create a unique name...
            while (names.ContainsKey(name))
                name = String.Format("{0}-{1}",
                                     baseName, ++tieBreaker);

            // Add the name to the keys
            names.Add(name, true);

            // Return the generated name
            return name;
        }

        #endregion
    }
}